const fs = require("fs");
const path = require("path");
const fsPromises = require("node:fs/promises");

/**
 * 复制目录与其子目录
 *
 * @param {string} srcDir 源目录路径
 * @param {string} targetDir 目标目录路径
 * @returns
 */
function copyDir(srcDir, targetDir) {
  // 判断源路径是否存在
  if (!fs.existsSync(srcDir)) {
    console.log(`源路径 ${srcDir} 不存在！`);
    return;
  }
  // 判断目标路径是否存在，不存在则创建目标路径
  if (!fs.existsSync(targetDir)) {
    fs.mkdirSync(targetDir);
  }
  // 读取源路径中的所有文件和子文件夹
  const files = fs.readdirSync(srcDir);

  // 循环遍历文件和子文件夹，并实现复制
  for (const fileName of files) {
    // 创建源文件/子文件夹的完整路径
    const srcFilePath = path.join(srcDir, fileName);
    // 创建目标文件/子文件夹的完整路径
    const targetFilePath = path.join(targetDir, fileName);

    // 获取文件/子文件夹的状态信息
    const stat = fs.statSync(srcFilePath);
    if (stat.isFile()) {
      // 如果是文件，则直接复制
      fs.copyFileSync(srcFilePath, targetFilePath);
      console.log(`复制文件 ${srcFilePath} 到 ${targetFilePath}`);
    } else if (stat.isDirectory()) {
      // 如果是子文件夹，则递归调用 copyDir 函数
      copyDir(srcFilePath, targetFilePath);
    }
  }

  console.log("copyDir success");
}

/**
 * 复制目录与其子目录
 * v16.7.0 新增了 fs.cp() api
 *
 * @param {string} srcDir 源目录路径
 * @param {string} targetDir 目标目录路径
 */
function copyDirByCp(srcDir, targetDir) {
  // 复制目录
  fs.cp(srcDir, targetDir, { recursive: true }, (err) => {
    if (err) {
      console.log("copyDirByCp fail");
      console.error(err);
    }
    console.log("copyDirByCp success");
  });
}

/**
 * 复制文件
 * v16.7.0 新增了 fs.cp() api
 *
 * @param {string} srcFile 源文件
 * @param {string} targetFile 目标文件
 */
function copyFilesByCp(srcFile, targetFile) {
  fs.cp(srcFile, targetFile, (err) => {
    if (err) {
      console.log("copyFilesByCp fail");
      console.error(err);
    }
    console.log("copyFilesByCp success");
  });
}

async function copyDirByCpPromise(srcDir, targetDir) {
  // 复制目录
  try {
    await fsPromises.cp(srcDir, targetDir, { recursive: true });
  } catch (error) {
    console.log("copy dir failed");
  }
}

/**
 * 复制目录下的文件（不包含子目录）
 *
 * @param {string} srcDir 源目录路径
 * @param {string} targetDir 目标目录路径
 * @returns
 */
function copyFiles(srcDir, targetDir) {
  // 判断源路径是否存在
  if (!fs.existsSync(srcDir)) {
    console.log(`源路径 ${srcDir} 不存在！`);
    return;
  }
  // 判断目标路径是否存在，不存在则创建目标路径
  if (!fs.existsSync(targetDir)) {
    fs.mkdirSync(targetDir);
  }

  fs.readdir(srcDir, (err, files) => {
    if (err) throw err;

    files.forEach((file) => {
      const sourceFilePath = path.join(srcDir, file);
      const destFilePath = path.join(targetDir, file);

      if (!fs.statSync(sourceFilePath).isFile()) {
        return;
      }

      fs.copyFile(sourceFilePath, destFilePath, (err) => {
        if (err) throw err;
        console.log(`${file} copied successfully.`);
      });
    });
  });
}

/**
 * 复制目录下的文件（不包含子目录）
 * 采用流的方式
 *
 * @param {string} srcDir 源目录路径
 * @param {string} targetDir 目标目录路径
 * @returns
 */
function copyFilesWithStream(srcDir, targetDir) {
  // 判断源路径是否存在
  if (!fs.existsSync(srcDir)) {
    console.log(`源路径 ${srcDir} 不存在！`);
    return;
  }
  // 判断目标路径是否存在，不存在则创建目标路径
  if (!fs.existsSync(targetDir)) {
    fs.mkdirSync(targetDir);
  }

  fs.readdir(srcDir, (err, files) => {
    if (err) throw err;

    files.forEach((file) => {
      const sourceFilePath = path.join(srcDir, file);
      const destFilePath = path.join(targetDir, file);

      if (!fs.statSync(sourceFilePath).isFile()) {
        return;
      }

      const readStream = fs.createReadStream(sourceFilePath);
      const writeStream = fs.createWriteStream(destFilePath);

      readStream.pipe(writeStream);
    });
  });

  console.log("copyFiles success");
}

// 测试

// copyDir("D:\\Desktop\\test", "D:\\Desktop\\test1");
// copyDirByCp("D:\\Desktop\\test", "D:\\Desktop\\test2");
// copyFilesByCp("D:\\Desktop\\test\\a.txt", "D:\\Desktop\\test\\a-1.txt");
// copyFiles("D:\\Desktop\\test", "D:\\Desktop\\test3");
// copyFilesWithStream("D:\\Desktop\\test", "D:\\Desktop\\test4");

copyDirByCpPromise("D:\\Desktop\\test", "D:\\Desktop\\test1");
